<?php
namespace Huang\PhpPersonalTools;

class TreeService
{
    private static $formatTree;//用于树型数组完成递归格式的全局变量

    /**
     * @description 根据指定父类获取子类集合
     * @param $targetCodes    指定code 有可能是字符串有可能是数组
     * @param $categoriesArr  查询的分类表数据
     * @param string $codeField code字段
     * @param string $idField id
     * @param string $parentIdField
     * @return array
     */
    public static function collectSubCategoryCodesByCode($targetCodes, $categoriesArr, $codeField = 'code', $idField = 'id', $parentIdField = 'pid')
    {
        $allCodes = []; // 初始化结果数组，用于存储所有收集到的codes
        $targetCodes = is_array($targetCodes) ? $targetCodes : [$targetCodes];
        // 查找匹配的子类及其所有父类的code，包含起始的targetCode
        function findSubCodesRecursively($currentCode, &$categories, &$codes, $codeField, $idField, $parentIdField)
        {
            $currentItem = array_filter($categories, function ($item) use ($currentCode, $codeField) {
                return $item[$codeField] === $currentCode;
            });
            $currentItem = reset($currentItem);

            if ($currentItem) {
                $codes[] = $currentItem[$codeField];
                $subItems = array_filter($categories, function ($item) use ($currentItem, $idField, $parentIdField) {
                    return $item[$parentIdField] === $currentItem[$idField];
                });

                foreach ($subItems as $subItem) {
                    findSubCodesRecursively($subItem[$codeField], $categories, $codes, $codeField, $idField, $parentIdField);
                }
            }
        }

        foreach ($targetCodes as $targetCode) {
            $codes = []; // 每个targetCode的codes集合
            findSubCodesRecursively($targetCode, $categoriesArr, $codes, $codeField, $idField, $parentIdField);
            // 合并结果
            $allCodes = array_merge($allCodes, $codes);
        }
        // 去重
        $uniqueCodes = array_unique($allCodes);
        return $uniqueCodes; // 返回所有收集的唯一codes数组
    }


    /**
     * @param $menu
     * @param int $id
     * @param int $level
     * @return array
     * @name: menulist
     * @describe:菜单格式化
     */
    public static function menulist($menu, $id = 0, $level = 0)
    {
        static $menus = array();
        $size = count($menus) - 1;
        foreach ($menu as $value) {
            if ($value['pid'] == $id) {
                $value['level'] = $level + 1;
                if ($level == 0) {
                    $value['str'] = str_repeat('', $value['level']);
                    $menus[] = $value;
                } elseif ($level == 2) {
                    $value['str'] = '&emsp;&emsp;&emsp;&emsp;' . '└ ';
                    $menus[$size]['children'][] = $value;
                } elseif ($level == 3) {
                    $value['str'] = '&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;' . '└ ';
                    $menus[$size]['children'][] = $value;
                } else {
                    $value['str'] = '&emsp;&emsp;' . '└ ';
                    $menus[$size]['children'][] = $value;
                }
                self::menulist($menu, $value['id'], $value['level']);
            }
        }
        return $menus;
    }

    /**
     * Notes:把返回的数据集转换成Tree
     * @param $list
     * @param $pk
     * @param $pid
     * @param $child
     * @param $root
     * @return array
     */
    public static function listToTree($list, $root = 0, $pk = 'id', $pid = 'pid', $child = 'children')
    {
        // 创建Tree
        $tree = [];
        if (is_array($list)) {
            // 创建基于主键的数组引用
            $refer = array();
            foreach ($list as $key => $data) {
                $refer[$data[$pk]] =& $list[$key];
            }
            foreach ($list as $key => $data) {
                // 判断是否存在parent
                $parentId = $data[$pid];
                if ($root == $parentId) {
                    $tree[] =& $list[$key];
                } else {
                    if (isset($refer[$parentId])) {
                        $parent =& $refer[$parentId];
                        $parent['childs'][] = $data[$pk];
                        $parent[$child][] =& $list[$key];
                    }
                }
            }
        }
        return $tree;
    }

    /*
     * children树形
     */
    public static function childTreeArr($tree,$pid = 0,$level=1,$pk = 'id', $pidfield = 'pid', $son ='children',$nameFiled='name')
    {
        $arr = [];
        foreach ($tree as $key => &$item) {
            if ($item["$pidfield"] == $pid) {
                $item['level'] = $level;
                $item['name'] = $item["$nameFiled"];
                $item[$son] = self::childTreeArr($tree, $item["$pk"], $level + 1,$pk,$pidfield,$son,$nameFiled);
                $arr[] = $item;
            }
        }
        return $arr;
    }


    /**
     * 将树子节点加层级成列表
     */
    public static function toFormatTree($list, $title = 'name', $pk = 'id', $pid = 'pid', $root = 0)
    {
        if (empty($list)) {
            return false;
        }
        $list = self::listToTree($list, $root, $pk, $pid);
        //dump($list);
        self::$formatTree = $data = [];
        self::_toFormatTree($list);
        foreach (self::$formatTree as $key => $value) {
            $index = ($key + 1);
            $next_parentid = isset(self::$formatTree[$index][$pid]) ? self::$formatTree[$index][$pid] : '';
            $value['level_show'] = self::catEmptyDeal($value, $next_parentid);
            $value['title_show'] = $value['level_show'] . $value[$title];
            $data[] = $value;
        }
        return $data;
    }

    protected static function _toFormatTree($tree, $level = 1)
    {
        foreach ($tree as $key => $value) {
            $temp = $value;
            if (isset($temp['chidren'])) {
                $temp['chidren'] = true;
                $temp['level'] = $level;
            } else {
                $temp['chidren'] = false;
                $temp['level'] = $level;
            }
            array_push(self::$formatTree, $temp);
            if (isset($value['chidren'])) {
                self::_toFormatTree($value['chidren'], ($level + 1));
            }
        }
    }

    public static function catEmptyDeal($cat, $next_parentid, $pid = 'pid', $empty = " ")
    {
        $str = "";
        if ($cat[$pid]) {
            for ($i = 2; $i < $cat['level']; $i++) {
                $str .= $empty . "│";
            }
            if ($cat[$pid] != $next_parentid && !$cat['children']) {
                $str .= $empty . "└─ ";
            } else {
                $str .= $empty . "├─ ";
            }
        }
        return $str;
    }

    /**
     * 传递父级id返回所有子级分类
     * @param $categorys  分类数组
     * @param int $catId 指定分类
     * @param varchar $pid 表中的pid字段
     * @param varchar $id 表中的id字段
     * @return array      返回分类下子集的数组
     */
    public static function getSonsByParentId($arr, $catId = 0, $pid = 'pid', $id = 'id')
    {
        $subs = array();
        foreach ($arr as $item) {
            if ($item[$pid] == $catId) {
                $subs[] = $item[$id];
                $subs = array_merge($subs, self::getSonsByParentId($arr, $item[$id], $pid, $id));
            }
        }
        array_push($subs, $catId);
        return array_unique($subs);
    }

    //传递一个子分类ID返回他的所有父级分类
    public static function getParents($cate, $id, $pid = 'pid', $idkey = 'id')
    {
        $arr = array();
        foreach ($cate as $v) {
            if ($v["$idkey"] == $id) {
                $arr[] = $v;
                $arr = array_merge(self::getParents($cate, $v["$pid"]), $arr);
            }
        }
        return $arr;
    }

    /**
     * 获取分类的全路径
     *
     * @param int $categoryId 分类ID
     * @param array $categories 分类数据数组
     * @param string $separator 分隔符
     * @return string 返回分类的全路径字符串
     */
  public static function getCategoryFullPath($categoryId, $categories, $separator = ' > ',$idField='id',$parentIdField='pid',$nameField='name') {
        $path = [];
        // 递归查找分类路径
        function findPath($id, &$path, $cats,$idField,$parentIdField,$nameField){
            foreach ($cats as $cat) {
                if ($cat["{$idField}"] == $id) {
                    array_unshift($path, $cat["$nameField"]); // 添加到路径的开头
                    if ($cat["$parentIdField"] != 0) { // 如果不是根分类，则继续向上查找
                        findPath($cat["$parentIdField"], $path, $cats,$idField,$parentIdField,$nameField);
                    }
                    break;
                }
            }
        }

        findPath($categoryId, $path, $categories,$idField,$parentIdField,$nameField);
        return implode($separator, $path); // 使用分隔符连接路径数组并返回
    }


    //根据指定id获取路径
    public static function getCategoryPath($categories, $categoryId,$sep='-',$idField='id',$pidField='pid',$nameFiled="name", &$path = '')
    {
        foreach ($categories as $category) {
            if ($category[$idField] == $categoryId) {
                $path = $category[$nameFiled] . ($path ? ($sep . $path) : '');
                // 如果不是顶级分类，继续向上查找
                if ($category[$pidField] > 0) {
                    self::getCategoryPath($categories, $category[$pidField],$sep,$idField,$pidField,$nameFiled, $path);
                }
                break;
            }
        }
        return $path;
    }

    /**---------------根据path字段进行操作start---------------**/
    /**
     * @description  获取所有子集
     * @param $table  表名
     * @param $id    指定的id 支持字符串和数组
     * @param $idField id字段名
     * @param $where  查询的额外条件
     * @param $withself 是否包含自己
     * @return array
     */
    public static function getSonIds($table, $id = [], $idField = 'id', $where = [], $withself = true)
    {
        $res = self::getDescendants($id, $table, $idField, $where);
        $ids = array_column($res, $idField);
        if ($withself) {
            $ids = array_merge($ids, $id);
        }
        return $ids;
    }

    /**
     * 获取所有祖先节点
     */
    public static function getAncestors($id = [], $table, $idField = 'id', $where = [])
    {
        $id = is_array($id) ? implode(',', $id) : $id;
        $map['child.' . $idField] = ['in', $id];
        $map = array_merge($map, $where);
        return db($table)->alias('child')
            ->join("{$table} parent", "FIND_IN_SET(parent.$idField, REPLACE(child.path, '-', ',')")
            ->where($map)
            ->field("parent.*")->select();
    }

    /**
     * 获取所有后代节点
     */
    public static function getDescendants($id = [], $table, $idField = 'id', $where = [])
    {
        $id = is_array($id) ? implode(',', $id) : $id;
        $map['parent.' . $idField] = ['in', $id];
        $map = array_merge($map, $where);
        return db($table)->alias('parent')
            ->join("{$table} child", "child.path LIKE CONCAT(parent.path, '-%')")
            ->where($map)
            ->field("child.*")->select();
    }

    /**
     * 指定id获取全路径
     */
    public static function getPath($id, $table, $idField = 'id',$nameField = 'name',$sep = '|',$where = [])
    {
        $map['p.'. $idField] = $id;
        $map = array_merge($map, $where);
        $res = db($table)->alias('p')
            ->join("{$table} c", "FIND_IN_SET(c.$idField, REPLACE(p.path, '-', ','))")
            ->where($map)
            ->value("GROUP_CONCAT(c.$nameField ORDER BY FIND_IN_SET(c.$idField, REPLACE(p.path, '-', ',')) SEPARATOR '$sep')");
        return $res;
    }
    /**---------------根据path字段进行操作end---------------**/

}
